//===============================================================================
// Copyright (C) 2008 Charles River Media. All rights reserved.
// 
// Catmull-Clark subdivision surface viewer program
//
// The developer of the code is
// Gyorgy Antal <gyantal@gmail.com>
//
// Contributor(s):
// Laszlo Szirmay-Kalos <szirmay@iit.bme.hu>
//
// The software was developed for the chapter 
// "Fast Evaluation of Subdivision Surfaces on DirectX10 Graphics Hardware"
// of the book ShaderX 6: Advanced Rendering Techniques, 
// edited by Wolfgang Engel,
// the appropriate section edited by Tom Forsyth. 
//
// The files are provided without support, instruction, or implied warranty of any
// kind.  Charles River Media makes no guarantee of its fitness for a particular purpose and is
// not liable under any circumstances for any damages or loss whatsoever arising
// from the use or inability to use this file or items derived from it.
//
// The source code can be found in the RenderVista project: 
// http://code.google.com/p/rendervista/source
// More specifically on this site:
// http://rendervista.googlecode.com/svn/trunk/Projects/DX10Subdivision/
//===============================================================================
// File: Shader.fx
//
// Description:
//===============================================================================

Buffer<float4> g_vertPosValenceBuffer;
Buffer<double2> g_texUvBuffer;	// put into separate Buffer, so if a game developer do not need for example normals, it is easy for him te exclude
Buffer<float3> g_normalBuffer;
Buffer<float3> g_tangentBuffer;

Buffer<uint4> g_quadAndAdjacentVerticesBuffer;
Buffer<uint4> g_quadTextureIndBuffer;
Buffer<uint4> g_quadNormalIndBuffer;
Buffer<uint4> g_quadTangentIndBuffer;




//-----------------------------------------------------------------------------------------
// Textures and Samplers
//-----------------------------------------------------------------------------------------
Texture2D g_texDiffuse;
Texture2D g_texNormalMap;

SamplerState g_diffuseSampler
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

SamplerState g_normalMapSampler
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

cbuffer cb2
{
	float4 g_ambient = float4(0.515,0.527,0.6,0.0);
	
    float g_kDiffuse = 1.0;
    float g_kSpecular = 0.5;
    float4 g_lightDiffuseColor = float4(1.0,0.972,0.909, 0.0);
    //float3 g_lightInvDirNormalized = float3(1.0,1.0,1.0);	// be sure it is normalized    
    //float3 g_lightInvDirNormalized = float3(-0.5773502691,0.5773502691,-0.5773502691);		// 0.5773 = 1/3 squared
    //float3 g_lightInvDirNormalized = float3(0, 1.3,-1.0);		// 0.5773 = 1/3 squared  // for cube
    //float3 g_lightInvDirNormalized = float3(1, 1, -1.0);		// 0.5773 = 1/3 squared // for lizard, original side
    float3 g_lightInvDirNormalized = float3(-1, 1, -1.0);		// 0.5773 = 1/3 squared // for lizard, other side
};


cbuffer cbEveryFrame
{
    float4x4 g_mWorldViewProj;
    float3 g_vEyePt;
};




//--------------------------------------------------------------------------------------
struct VS_INPUT
{
    uint QuadIndex : POSINDEX;
};

struct GS_INPUT
{
    uint QuadIndex : POSINDEX;
};

// max 68 vertex can be emitted = 1024/15, (since the DX limit of max 1024 floats)
struct PS_INPUT
{
    half4 Pos : SV_POSITION;
    double2 TexUv : TEXCOORD0;
	half3 NormalInWorld : NORMAL;
	half3 TangentInWorld : TEXCOORD1;
	half3 PosInWorld : POSVIEW;
};		// 15 float per vertex


//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
GS_INPUT VSMain(VS_INPUT input)
{
    GS_INPUT output = (GS_INPUT)0;
    output.QuadIndex = input.QuadIndex;
    return output;
}

void Subdiv0Function(uint p_quadIndex, inout TriangleStream<PS_INPUT> p_stream)
{
	PS_INPUT output;
	
	int quadBase = 6 * p_quadIndex;
	uint4 quadInd = g_quadAndAdjacentVerticesBuffer.Load(quadBase);
	
	uint4 texInd = g_quadTextureIndBuffer.Load(p_quadIndex);
    uint4 normalInd = g_quadNormalIndBuffer.Load(p_quadIndex);
    uint4 tangentInd = g_quadTangentIndBuffer.Load(p_quadIndex);
    
	float3 v1 = g_vertPosValenceBuffer.Load(quadInd.x).xyz;
    float3 v2 = g_vertPosValenceBuffer.Load(quadInd.y).xyz;
    float3 v3 = g_vertPosValenceBuffer.Load(quadInd.z).xyz;
    float3 v4 = g_vertPosValenceBuffer.Load(quadInd.w).xyz;
    
	float2 t1 = g_texUvBuffer.Load(texInd.x);
    float2 t2 = g_texUvBuffer.Load(texInd.y);
    float2 t3 = g_texUvBuffer.Load(texInd.z);
    float2 t4 = g_texUvBuffer.Load(texInd.w);

    float3 n1 = g_normalBuffer.Load(normalInd.x);
    float3 n2 = g_normalBuffer.Load(normalInd.y);
    float3 n3 = g_normalBuffer.Load(normalInd.z);
    float3 n4 = g_normalBuffer.Load(normalInd.w);
    
	float3 tan1 = g_tangentBuffer.Load(tangentInd.x);
    float3 tan2 = g_tangentBuffer.Load(tangentInd.y);
    float3 tan3 = g_tangentBuffer.Load(tangentInd.z);
    float3 tan4 = g_tangentBuffer.Load(tangentInd.w);
    
	output.PosInWorld = v1;
	output.Pos = mul(float4(v1.xyz, 1.0), g_mWorldViewProj);
    output.TexUv = t1;
    output.NormalInWorld = n1;
    output.TangentInWorld = tan1;
    p_stream.Append(output);
    
	output.PosInWorld = v3;
    output.Pos = mul(float4(v3.xyz, 1.0), g_mWorldViewProj);
    output.TexUv = t3;
    output.NormalInWorld = n3;
    output.TangentInWorld = tan3;
    p_stream.Append(output);
    
	output.PosInWorld = v2;
	output.Pos = mul(float4(v2.xyz, 1.0), g_mWorldViewProj);
    output.TexUv = t2;
    output.NormalInWorld = n2;
    output.TangentInWorld = tan2;
    p_stream.Append(output);

    output.PosInWorld = v4;
    output.Pos = mul(float4(v4.xyz, 1.0), g_mWorldViewProj);
    output.TexUv = t4;
    output.NormalInWorld = n4;
    output.TangentInWorld = tan4;
    p_stream.Append(output);

    p_stream.RestartStrip(); 
}


void Subdiv1Function(uint p_quadIndex, inout TriangleStream<PS_INPUT> p_stream)
{
	PS_INPUT output;
	
	int quadBase = 6 * p_quadIndex;
	uint4 quadInd = g_quadAndAdjacentVerticesBuffer.Load(quadBase);
	
	uint4 texInd = g_quadTextureIndBuffer.Load(p_quadIndex);
	uint4 normalInd = g_quadNormalIndBuffer.Load(p_quadIndex);
	uint4 tangentInd = g_quadTangentIndBuffer.Load(p_quadIndex);
	
	float4 vpv1 = g_vertPosValenceBuffer.Load(quadInd.x);
	float4 vpv2 = g_vertPosValenceBuffer.Load(quadInd.y);
	float4 vpv3 = g_vertPosValenceBuffer.Load(quadInd.z);
	float4 vpv4 = g_vertPosValenceBuffer.Load(quadInd.w);
		
	float3 v1 = vpv1.xyz;
	float3 v2 = vpv2.xyz;
	float3 v3 = vpv3.xyz;
	float3 v4 = vpv4.xyz;

	uint val1 = vpv1.w;	// there is a float to int conversion here!
	uint val2 = vpv2.w;
	uint val3 = vpv3.w;
	uint val4 = vpv4.w;
		
	int4 adjData1 = g_quadAndAdjacentVerticesBuffer.Load(quadBase + 1);
	int4 adjData2 = g_quadAndAdjacentVerticesBuffer.Load(quadBase + 2);
	int4 adjData3 = g_quadAndAdjacentVerticesBuffer.Load(quadBase + 3);
	int4 adjData4 = g_quadAndAdjacentVerticesBuffer.Load(quadBase + 4);
	int4 adjData5 = g_quadAndAdjacentVerticesBuffer.Load(quadBase + 5);
	
	
	/*
	// 1084 / 863 fps, so it is slower, but it is not logical why it is slower
	// v11
	float3 v11 = g_vertPosValenceBuffer.Load(adjData1.x).xyz;
	float3 v12 = g_vertPosValenceBuffer.Load(adjData1.y).xyz;
	float3 v13 = g_vertPosValenceBuffer.Load(adjData1.z).xyz;
	float3 v14 = g_vertPosValenceBuffer.Load(adjData1.w).xyz;
	float3 v15 = g_vertPosValenceBuffer.Load(adjData2.x).xyz;
	float3 v1Last;
	if (val1 == 3)
		v1Last = v11;
	else if (val1 == 4)
		v1Last = v13;
	else
		v1Last = v15;
		
	// v21
	float3 v21 = g_vertPosValenceBuffer.Load(adjData2.y).xyz;
	float3 v22 = g_vertPosValenceBuffer.Load(adjData2.z).xyz;
	float3 v23 = g_vertPosValenceBuffer.Load(adjData2.w).xyz;
	float3 v24 = g_vertPosValenceBuffer.Load(adjData3.x).xyz;
	float3 v25 = g_vertPosValenceBuffer.Load(adjData3.y).xyz;

	float3 v2Last;
	if (val2 == 3)
		v2Last = v21;
	else if (val2 == 4)
		v2Last = v23;
	else
		v2Last = v25;	
	
	// v31
	float3 v31 = g_vertPosValenceBuffer.Load(adjData3.z).xyz;
	float3 v32 = g_vertPosValenceBuffer.Load(adjData3.w).xyz;
	float3 v33 = g_vertPosValenceBuffer.Load(adjData4.x).xyz;
	float3 v34 = g_vertPosValenceBuffer.Load(adjData4.y).xyz;
	float3 v35 = g_vertPosValenceBuffer.Load(adjData4.z).xyz;
	float3 v3Last;
	if (val3 == 3)
		v3Last = v31;
	else if (val3 == 4)
		v3Last = v33;
	else
		v3Last = v35;	
		
	// v41
	float3 v41 = g_vertPosValenceBuffer.Load(adjData4.w).xyz;
	float3 v42 = g_vertPosValenceBuffer.Load(adjData5.x).xyz;
	float3 v43 = g_vertPosValenceBuffer.Load(adjData5.y).xyz;
	float3 v44 = g_vertPosValenceBuffer.Load(adjData5.z).xyz;
	float3 v45 = g_vertPosValenceBuffer.Load(adjData5.w).xyz;
	float3 v4Last;
	if (val4 == 3)
		v4Last = v41;
	else if (val4 == 4)
		v4Last = v43;
	else
		v4Last = v45;	
	*/
			

	// 1137 / 1080 fps
	// v11
	int v11Ind = adjData1.x;
	float3 v11 = g_vertPosValenceBuffer.Load(v11Ind).xyz;

	int v12Ind = adjData1.y;
	float3 v12 = g_vertPosValenceBuffer.Load(v12Ind).xyz;
	int v13Ind = adjData1.z;
	float3 v13 = g_vertPosValenceBuffer.Load(v13Ind).xyz;

	int v14Ind = adjData1.w;
	float3 v14 = g_vertPosValenceBuffer.Load(v14Ind).xyz;
	int v15Ind = adjData2.x;
	float3 v15 = g_vertPosValenceBuffer.Load(v15Ind).xyz;

	int v1LastInd;
	if (val1 == 3)
		v1LastInd = v11Ind;
	else if (val1 == 4)
		v1LastInd = v13Ind;
	else
		v1LastInd = v15Ind;
	float3 v1Last = g_vertPosValenceBuffer.Load(v1LastInd).xyz;
	
	// v21
	int v21Ind = adjData2.y;
	float3 v21 = g_vertPosValenceBuffer.Load(v21Ind).xyz;

	int v22Ind = adjData2.z;
	float3 v22 = g_vertPosValenceBuffer.Load(v22Ind).xyz;
	int v23Ind = adjData2.w;
	float3 v23 = g_vertPosValenceBuffer.Load(v23Ind).xyz;

	int v24Ind = adjData3.x;
	float3 v24 = g_vertPosValenceBuffer.Load(v24Ind).xyz;
	int v25Ind = adjData3.y;
	float3 v25 = g_vertPosValenceBuffer.Load(v25Ind).xyz;

	int v2LastInd;
	if (val2 == 3)
		v2LastInd = v21Ind;
	else if (val2 == 4)
		v2LastInd = v23Ind;
	else
		v2LastInd = v25Ind;
	float3 v2Last = g_vertPosValenceBuffer.Load(v2LastInd).xyz;
	
	// v31
	int v31Ind = adjData3.z;
	float3 v31 = g_vertPosValenceBuffer.Load(v31Ind).xyz;

	int v32Ind = adjData3.w;
	float3 v32 = g_vertPosValenceBuffer.Load(v32Ind).xyz;
	int v33Ind = adjData4.x;
	float3 v33 = g_vertPosValenceBuffer.Load(v33Ind).xyz;

	int v34Ind = adjData4.y;
	float3 v34 = g_vertPosValenceBuffer.Load(v34Ind).xyz;
	int v35Ind = adjData4.z;
	float3 v35 = g_vertPosValenceBuffer.Load(v35Ind).xyz;

	int v3LastInd;
	if (val3 == 3)
		v3LastInd = v31Ind;
	else if (val3 == 4)
		v3LastInd = v33Ind;
	else
		v3LastInd = v35Ind;
	float3 v3Last = g_vertPosValenceBuffer.Load(v3LastInd).xyz;
	
	// v41
	int v41Ind = adjData4.w;
	float3 v41 = g_vertPosValenceBuffer.Load(v41Ind).xyz;

	int v42Ind = adjData5.x;
	float3 v42 = g_vertPosValenceBuffer.Load(v42Ind).xyz;
	int v43Ind = adjData5.y;
	float3 v43 = g_vertPosValenceBuffer.Load(v43Ind).xyz;

	int v44Ind = adjData5.z;
	float3 v44 = g_vertPosValenceBuffer.Load(v44Ind).xyz;
	int v45Ind = adjData5.w;
	float3 v45 = g_vertPosValenceBuffer.Load(v45Ind).xyz;

	int v4LastInd;
	if (val4 == 3)
		v4LastInd = v41Ind;
	else if (val4 == 4)
		v4LastInd = v43Ind;
	else
		v4LastInd = v45Ind;
	float3 v4Last = g_vertPosValenceBuffer.Load(v4LastInd).xyz;

	


	float3 a5 = (v1 + v2 + v3 + v4) / 4.0f;
	float3 a2 = (6 * (v1 + v2) + v1Last + v21 + v3 + v4) / 16.0f;
	float3 a6 = (6 * (v2 + v4) + v2Last + v41 + v1 + v3) / 16.0f;
	float3 a8 = (6 * (v4 + v3) + v4Last + v31 + v1 + v2) / 16.0f;
	float3 a4 = (6 * (v3 + v1) + v3Last + v11 + v2 + v4) / 16.0f;
	
	//float3 a2 = (v1 + v2) / 2.0f;
	//float3 a6 = (v2 + v4) / 2.0f;
	//float3 a8 = (v4 + v3) / 2.0f;
	//float3 a4 = (v3 + v1) / 2.0f;
	
	float3 a1;
	float3 a3;
	float3 a7;
	float3 a9;
	
		
	if (val1 == 3)
		a1 = (15 * v1 + 6 * (v11 + v2 + v3) + v3Last + v21 + v4) / 36;
	else if (val1 == 4)
		a1 = (36 * v1 + 6 * (v11 + v13 + v2 + v3) + v3Last + v12 + v21 + v4) / 64;
	else
		a1 = (65 * v1 + 6 * (v11 + v13 + v15 + v2 + v3) + v3Last + v12 + v14 + v21 + v4) / 100;

	if (val2 == 3)
		a3 = (15 * v2 + 6 * (v21 + v1 + v4) + v1Last + v41 + v3) / 36;
	else if (val2 == 4)
		a3 = (36 * v2 + 6 * (v21 + v23 + v1 + v4) + v1Last + v22 + v41 + v3) / 64;
	else
		a3 = (65 * v2 + 6 * (v21 + v23 + v25 + v1 + v4) + v1Last + v22 + v24 + v41 + v3) / 100;

	if (val3 == 3)
		a7 = (15 * v3 + 6 * (v31 + v1 + v4) + v4Last + v11 + v2) / 36;
	else if (val3 == 4)
		a7 = (36 * v3 + 6 * (v31 + v33 + v1 + v4) + v4Last + v32 + v11 + v2) / 64;
	else
		a7 = (65 * v3 + 6 * (v31 + v33 + v35 + v1 + v4) + v4Last + v32 + v34 + v11 + v2) / 100;

	if (val4 == 3)
		a9 = (15 * v4 + 6 * (v41 + v2 + v3) + v2Last + v31 + v1) / 36;
	else if (val4 == 4)
		a9 = (36 * v4 + 6 * (v41 + v43 + v2 + v3) + v2Last + v42 + v31 + v1) / 64;
	else
		a9 = (65 * v4 + 6 * (v41 + v43 + v45 + v2 + v3) + v2Last + v42 + v44 + v31 + v1) / 100;
		
/*
 // somehow, the following optimization is 20% better in speed sometimes, depend on driver
 //  but, if Flow control is available this optimization gains more
	a1 = 6 * (v11 + v2 + v3) + v3Last + v21 + v4;
	if (val1 == 3)
		a1 = (15 * v1 + a1) / 36;
	else if (val1 == 4)
		a1 = (36 * v1 + 6 * (v13) + v12 + a1) / 64;
	else
		a1 = (65 * v1 + 6 * (v13 + v15) +  v12 + v14 + a1) / 100;

	a3 = 6 * (v21 + v1 + v4) + v1Last + v41 + v3;
	if (val2 == 3)
		a3 = (15 * v2 + a3) / 36;
	else if (val2 == 4)
		a3 = (36 * v2 + 6 * (v23) + v22 + a3) / 64;
	else
		a3 = (65 * v2 + 6 * (v23 + v25) + v22 + v24 + a3) / 100;

	a7 = 6 * (v31 + v1 + v4) + v4Last + v11 + v2;
	if (val3 == 3)
		a7 = (15 * v3 + a7) / 36;
	else if (val3 == 4)
		a7 = (36 * v3 + 6 * (v33) + v32 + a7) / 64;
	else
		a7 = (65 * v3 + 6 * (v33 + v35) + v32 + v34 + a7) / 100;

	a9 = 6 * (v41 + v2 + v3) + v2Last + v31 + v1;
	if (val4 == 3)
		a9 = (15 * v4 + a9) / 36;
	else if (val4 == 4)
		a9 = (36 * v4 + 6 * (v43) +  v42 + a9) / 64;
	else
		a9 = (65 * v4 + 6 * (v43 + v45) +  v42 + v44 + a9) / 100;
*/


	// ********** texture and normal
	float2 t1 = g_texUvBuffer.Load(texInd.x);
	float2 t3 = g_texUvBuffer.Load(texInd.y);
	float2 t7 = g_texUvBuffer.Load(texInd.z);
	float2 t9 = g_texUvBuffer.Load(texInd.w);
	float2 t2 = (t1 + t3) / 2.0f;
	float2 t4 = (t1 + t7) / 2.0f;
	float2 t6 = (t3 + t9) / 2.0f;
	float2 t8 = (t7 + t9) / 2.0f;
	float2 t5 = (t4 + t6) / 2.0f;

	float3 n1 = g_normalBuffer.Load(normalInd.x);
	float3 n3 = g_normalBuffer.Load(normalInd.y);
	float3 n7 = g_normalBuffer.Load(normalInd.z);
	float3 n9 = g_normalBuffer.Load(normalInd.w);
	float3 n2 = (n1 + n3);
	float3 n4 = (n1 + n7);
	float3 n6 = (n3 + n9);
	float3 n8 = (n7 + n9);
	float3 n5 = (n4 + n6);
	
	float3 tan1 = g_tangentBuffer.Load(tangentInd.x);
    float3 tan3 = g_tangentBuffer.Load(tangentInd.y);
    float3 tan7 = g_tangentBuffer.Load(tangentInd.z);
    float3 tan9 = g_tangentBuffer.Load(tangentInd.w);
    float3 tan2 = (tan1 + tan3);
	float3 tan4 = (tan1 + tan7);
	float3 tan6 = (tan3 + tan9);
	float3 tan8 = (tan7 + tan9);
	float3 tan5 = (tan4 + tan6);
	
	// transform vertices here, save some matrix multiplication, 12 vertices out, only 9 transformation is performed here
	float4 a1t = mul(float4(a1.xyz, 1.0), g_mWorldViewProj);
	float4 a2t = mul(float4(a2.xyz, 1.0), g_mWorldViewProj);
	float4 a3t = mul(float4(a3.xyz, 1.0), g_mWorldViewProj);
	float4 a4t = mul(float4(a4.xyz, 1.0), g_mWorldViewProj);
	float4 a5t = mul(float4(a5.xyz, 1.0), g_mWorldViewProj);
	float4 a6t = mul(float4(a6.xyz, 1.0), g_mWorldViewProj);
	float4 a7t = mul(float4(a7.xyz, 1.0), g_mWorldViewProj);
	float4 a8t = mul(float4(a8.xyz, 1.0), g_mWorldViewProj);
	float4 a9t = mul(float4(a9.xyz, 1.0), g_mWorldViewProj);	
	
	
	output.PosInWorld = a1;
	output.Pos = mul(float4(a1.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t1;
	output.NormalInWorld = n1;
	output.TangentInWorld = tan1;
	p_stream.Append(output);
	
	output.PosInWorld = a4;
	output.Pos = mul(float4(a4.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t4;
	output.NormalInWorld = n4;
	output.TangentInWorld = tan4;
	p_stream.Append(output);
	
	output.PosInWorld = a2;
	output.Pos = mul(float4(a2.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t2;
	output.NormalInWorld = n2;
	output.TangentInWorld = tan2;
	p_stream.Append(output);

	output.PosInWorld = a5;
	output.Pos = mul(float4(a5.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t5;
	output.NormalInWorld = n5;
	output.TangentInWorld = tan5;
	p_stream.Append(output);

	output.PosInWorld = a3;
	output.Pos = mul(float4(a3.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t3;
	output.NormalInWorld = n3;
	output.TangentInWorld = tan3;
	p_stream.Append(output); 

	output.PosInWorld = a6;
	output.Pos = mul(float4(a6.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t6;
	output.NormalInWorld = n6;
	output.TangentInWorld = tan6;
	p_stream.Append(output);


	p_stream.RestartStrip(); 
	
	output.PosInWorld = a4;
	output.Pos = mul(float4(a4.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t4;
	output.NormalInWorld = n4;
	output.TangentInWorld = tan4;
	p_stream.Append(output);
	
	output.PosInWorld = a7;
	output.Pos = mul(float4(a7.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t7;
	output.NormalInWorld = n7;
	output.TangentInWorld = tan7;
	p_stream.Append(output);

	output.PosInWorld = a5;
	output.Pos = mul(float4(a5.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t5;
	output.NormalInWorld = n5;
	output.TangentInWorld = tan5;
	p_stream.Append(output);

	output.PosInWorld = a8;
	output.Pos = mul(float4(a8.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t8;
	output.NormalInWorld = n8;
	output.TangentInWorld = tan8;
	p_stream.Append(output);

	output.PosInWorld = a6;
	output.Pos = mul(float4(a6.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t6;
	output.NormalInWorld = n6;
	output.TangentInWorld = tan6;
	p_stream.Append(output);

	output.PosInWorld = a9;
	output.Pos = mul(float4(a9.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t9;
	output.NormalInWorld = n9;
	output.TangentInWorld = tan9;
	p_stream.Append(output); 
	
	
	/*
	output.PosInWorld = a1;
	output.Pos = a1t;
	output.TexUv = t1;
	output.NormalInWorld = n1;
	output.TangentInWorld = tan1;
	p_stream.Append(output);
	
	output.PosInWorld = a4;
	output.Pos = a4t;
	output.TexUv = t4;
	output.NormalInWorld = n4;
	output.TangentInWorld = tan4;
	p_stream.Append(output);
	
	output.PosInWorld = a2;
	output.Pos = a2t;
	output.TexUv = t2;
	output.NormalInWorld = n2;
	output.TangentInWorld = tan2;
	p_stream.Append(output);

	output.PosInWorld = a5;
	output.Pos = a5t;
	output.TexUv = t5;
	output.NormalInWorld = n5;
	output.TangentInWorld = tan5;
	p_stream.Append(output);

	output.PosInWorld = a3;
	output.Pos = a3t;
	output.TexUv = t3;
	output.NormalInWorld = n3;
	output.TangentInWorld = tan3;
	p_stream.Append(output); 

	output.PosInWorld = a6;
	output.Pos = a6t;
	output.TexUv = t6;
	output.NormalInWorld = n6;
	output.TangentInWorld = tan6;
	p_stream.Append(output);


	p_stream.RestartStrip(); 
	
	output.PosInWorld = a4;
	output.Pos = a4t;
	output.TexUv = t4;
	output.NormalInWorld = n4;
	output.TangentInWorld = tan4;
	p_stream.Append(output);
	
	output.PosInWorld = a7;
	output.Pos = a7t;
	output.TexUv = t7;
	output.NormalInWorld = n7;
	output.TangentInWorld = tan7;
	p_stream.Append(output);

	output.PosInWorld = a5;
	output.Pos = a5t;
	output.TexUv = t5;
	output.NormalInWorld = n5;
	output.TangentInWorld = tan5;
	p_stream.Append(output);

	output.PosInWorld = a8;
	output.Pos = a8t;
	output.TexUv = t8;
	output.NormalInWorld = n8;
	output.TangentInWorld = tan8;
	p_stream.Append(output);

	output.PosInWorld = a6;
	output.Pos = a6t;
	output.TexUv = t6;
	output.NormalInWorld = n6;
	output.TangentInWorld = tan6;
	p_stream.Append(output);

	output.PosInWorld = a9;
	output.Pos = a9t;
	output.TexUv = t9;
	output.NormalInWorld = n9;
	output.TangentInWorld = tan9;
	p_stream.Append(output); 
	*/

	p_stream.RestartStrip(); 

}



void Subdiv2Function(uint p_quadIndex, inout TriangleStream<PS_INPUT> p_stream)
{
	PS_INPUT output;
	
	int quadBase = 6 * p_quadIndex;
	uint4 quadInd = g_quadAndAdjacentVerticesBuffer.Load(quadBase);
	
	uint4 texInd = g_quadTextureIndBuffer.Load(p_quadIndex);
	uint4 normalInd = g_quadNormalIndBuffer.Load(p_quadIndex);
	uint4 tangentInd = g_quadTangentIndBuffer.Load(p_quadIndex);
	
	float4 vpv1 = g_vertPosValenceBuffer.Load(quadInd.x);
	float4 vpv2 = g_vertPosValenceBuffer.Load(quadInd.y);
	float4 vpv3 = g_vertPosValenceBuffer.Load(quadInd.z);
	float4 vpv4 = g_vertPosValenceBuffer.Load(quadInd.w);
		
	float3 v1 = vpv1.xyz;
	float3 v2 = vpv2.xyz;
	float3 v3 = vpv3.xyz;
	float3 v4 = vpv4.xyz;

	uint val1 = vpv1.w;	// there is a float to int conversion here!
	uint val2 = vpv2.w;
	uint val3 = vpv3.w;
	uint val4 = vpv4.w;
		
	int4 adjData1 = g_quadAndAdjacentVerticesBuffer.Load(quadBase + 1);
	int4 adjData2 = g_quadAndAdjacentVerticesBuffer.Load(quadBase + 2);
	int4 adjData3 = g_quadAndAdjacentVerticesBuffer.Load(quadBase + 3);
	int4 adjData4 = g_quadAndAdjacentVerticesBuffer.Load(quadBase + 4);
	int4 adjData5 = g_quadAndAdjacentVerticesBuffer.Load(quadBase + 5);
	
	
	/*
	// 1084 / 863 fps, so it is slower, but it is not logical why it is slower
	// v11
	float3 v11 = g_vertPosValenceBuffer.Load(adjData1.x).xyz;
	float3 v12 = g_vertPosValenceBuffer.Load(adjData1.y).xyz;
	float3 v13 = g_vertPosValenceBuffer.Load(adjData1.z).xyz;
	float3 v14 = g_vertPosValenceBuffer.Load(adjData1.w).xyz;
	float3 v15 = g_vertPosValenceBuffer.Load(adjData2.x).xyz;
	float3 v1Last;
	if (val1 == 3)
		v1Last = v11;
	else if (val1 == 4)
		v1Last = v13;
	else
		v1Last = v15;
		
	// v21
	float3 v21 = g_vertPosValenceBuffer.Load(adjData2.y).xyz;
	float3 v22 = g_vertPosValenceBuffer.Load(adjData2.z).xyz;
	float3 v23 = g_vertPosValenceBuffer.Load(adjData2.w).xyz;
	float3 v24 = g_vertPosValenceBuffer.Load(adjData3.x).xyz;
	float3 v25 = g_vertPosValenceBuffer.Load(adjData3.y).xyz;

	float3 v2Last;
	if (val2 == 3)
		v2Last = v21;
	else if (val2 == 4)
		v2Last = v23;
	else
		v2Last = v25;	
	
	// v31
	float3 v31 = g_vertPosValenceBuffer.Load(adjData3.z).xyz;
	float3 v32 = g_vertPosValenceBuffer.Load(adjData3.w).xyz;
	float3 v33 = g_vertPosValenceBuffer.Load(adjData4.x).xyz;
	float3 v34 = g_vertPosValenceBuffer.Load(adjData4.y).xyz;
	float3 v35 = g_vertPosValenceBuffer.Load(adjData4.z).xyz;
	float3 v3Last;
	if (val3 == 3)
		v3Last = v31;
	else if (val3 == 4)
		v3Last = v33;
	else
		v3Last = v35;	
		
	// v41
	float3 v41 = g_vertPosValenceBuffer.Load(adjData4.w).xyz;
	float3 v42 = g_vertPosValenceBuffer.Load(adjData5.x).xyz;
	float3 v43 = g_vertPosValenceBuffer.Load(adjData5.y).xyz;
	float3 v44 = g_vertPosValenceBuffer.Load(adjData5.z).xyz;
	float3 v45 = g_vertPosValenceBuffer.Load(adjData5.w).xyz;
	float3 v4Last;
	if (val4 == 3)
		v4Last = v41;
	else if (val4 == 4)
		v4Last = v43;
	else
		v4Last = v45;	
	*/
			

	// 1137 / 1080 fps
	// v11
	int v11Ind = adjData1.x;
	float3 v11 = g_vertPosValenceBuffer.Load(v11Ind).xyz;

	int v12Ind = adjData1.y;
	float3 v12 = g_vertPosValenceBuffer.Load(v12Ind).xyz;
	int v13Ind = adjData1.z;
	float3 v13 = g_vertPosValenceBuffer.Load(v13Ind).xyz;

	int v14Ind = adjData1.w;
	float3 v14 = g_vertPosValenceBuffer.Load(v14Ind).xyz;
	int v15Ind = adjData2.x;
	float3 v15 = g_vertPosValenceBuffer.Load(v15Ind).xyz;

	int v1LastInd;
	if (val1 == 3)
		v1LastInd = v11Ind;
	else if (val1 == 4)
		v1LastInd = v13Ind;
	else
		v1LastInd = v15Ind;
	float3 v1Last = g_vertPosValenceBuffer.Load(v1LastInd).xyz;
	
	// v21
	int v21Ind = adjData2.y;
	float3 v21 = g_vertPosValenceBuffer.Load(v21Ind).xyz;

	int v22Ind = adjData2.z;
	float3 v22 = g_vertPosValenceBuffer.Load(v22Ind).xyz;
	int v23Ind = adjData2.w;
	float3 v23 = g_vertPosValenceBuffer.Load(v23Ind).xyz;

	int v24Ind = adjData3.x;
	float3 v24 = g_vertPosValenceBuffer.Load(v24Ind).xyz;
	int v25Ind = adjData3.y;
	float3 v25 = g_vertPosValenceBuffer.Load(v25Ind).xyz;

	int v2LastInd;
	if (val2 == 3)
		v2LastInd = v21Ind;
	else if (val2 == 4)
		v2LastInd = v23Ind;
	else
		v2LastInd = v25Ind;
	float3 v2Last = g_vertPosValenceBuffer.Load(v2LastInd).xyz;
	
	// v31
	int v31Ind = adjData3.z;
	float3 v31 = g_vertPosValenceBuffer.Load(v31Ind).xyz;

	int v32Ind = adjData3.w;
	float3 v32 = g_vertPosValenceBuffer.Load(v32Ind).xyz;
	int v33Ind = adjData4.x;
	float3 v33 = g_vertPosValenceBuffer.Load(v33Ind).xyz;

	int v34Ind = adjData4.y;
	float3 v34 = g_vertPosValenceBuffer.Load(v34Ind).xyz;
	int v35Ind = adjData4.z;
	float3 v35 = g_vertPosValenceBuffer.Load(v35Ind).xyz;

	int v3LastInd;
	if (val3 == 3)
		v3LastInd = v31Ind;
	else if (val3 == 4)
		v3LastInd = v33Ind;
	else
		v3LastInd = v35Ind;
	float3 v3Last = g_vertPosValenceBuffer.Load(v3LastInd).xyz;
	
	// v41
	int v41Ind = adjData4.w;
	float3 v41 = g_vertPosValenceBuffer.Load(v41Ind).xyz;

	int v42Ind = adjData5.x;
	float3 v42 = g_vertPosValenceBuffer.Load(v42Ind).xyz;
	int v43Ind = adjData5.y;
	float3 v43 = g_vertPosValenceBuffer.Load(v43Ind).xyz;

	int v44Ind = adjData5.z;
	float3 v44 = g_vertPosValenceBuffer.Load(v44Ind).xyz;
	int v45Ind = adjData5.w;
	float3 v45 = g_vertPosValenceBuffer.Load(v45Ind).xyz;

	int v4LastInd;
	if (val4 == 3)
		v4LastInd = v41Ind;
	else if (val4 == 4)
		v4LastInd = v43Ind;
	else
		v4LastInd = v45Ind;
	float3 v4Last = g_vertPosValenceBuffer.Load(v4LastInd).xyz;

	


	float3 a5 = (v1 + v2 + v3 + v4) / 4.0f;
	float3 a2 = (6 * (v1 + v2) + v1Last + v21 + v3 + v4) / 16.0f;
	float3 a6 = (6 * (v2 + v4) + v2Last + v41 + v1 + v3) / 16.0f;
	float3 a8 = (6 * (v4 + v3) + v4Last + v31 + v1 + v2) / 16.0f;
	float3 a4 = (6 * (v3 + v1) + v3Last + v11 + v2 + v4) / 16.0f;
	
	//float3 a2 = (v1 + v2) / 2.0f;
	//float3 a6 = (v2 + v4) / 2.0f;
	//float3 a8 = (v4 + v3) / 2.0f;
	//float3 a4 = (v3 + v1) / 2.0f;
	
	float3 a1;
	float3 a3;
	float3 a7;
	float3 a9;
	
		
	if (val1 == 3)
		a1 = (15 * v1 + 6 * (v11 + v2 + v3) + v3Last + v21 + v4) / 36;
	else if (val1 == 4)
		a1 = (36 * v1 + 6 * (v11 + v13 + v2 + v3) + v3Last + v12 + v21 + v4) / 64;
	else
		a1 = (65 * v1 + 6 * (v11 + v13 + v15 + v2 + v3) + v3Last + v12 + v14 + v21 + v4) / 100;

	if (val2 == 3)
		a3 = (15 * v2 + 6 * (v21 + v1 + v4) + v1Last + v41 + v3) / 36;
	else if (val2 == 4)
		a3 = (36 * v2 + 6 * (v21 + v23 + v1 + v4) + v1Last + v22 + v41 + v3) / 64;
	else
		a3 = (65 * v2 + 6 * (v21 + v23 + v25 + v1 + v4) + v1Last + v22 + v24 + v41 + v3) / 100;

	if (val3 == 3)
		a7 = (15 * v3 + 6 * (v31 + v1 + v4) + v4Last + v11 + v2) / 36;
	else if (val3 == 4)
		a7 = (36 * v3 + 6 * (v31 + v33 + v1 + v4) + v4Last + v32 + v11 + v2) / 64;
	else
		a7 = (65 * v3 + 6 * (v31 + v33 + v35 + v1 + v4) + v4Last + v32 + v34 + v11 + v2) / 100;

	if (val4 == 3)
		a9 = (15 * v4 + 6 * (v41 + v2 + v3) + v2Last + v31 + v1) / 36;
	else if (val4 == 4)
		a9 = (36 * v4 + 6 * (v41 + v43 + v2 + v3) + v2Last + v42 + v31 + v1) / 64;
	else
		a9 = (65 * v4 + 6 * (v41 + v43 + v45 + v2 + v3) + v2Last + v42 + v44 + v31 + v1) / 100;
		
/*
 // somehow, the following optimization is 20% better in speed sometimes, depend on driver
 //  but, if Flow control is available this optimization gains more
	a1 = 6 * (v11 + v2 + v3) + v3Last + v21 + v4;
	if (val1 == 3)
		a1 = (15 * v1 + a1) / 36;
	else if (val1 == 4)
		a1 = (36 * v1 + 6 * (v13) + v12 + a1) / 64;
	else
		a1 = (65 * v1 + 6 * (v13 + v15) +  v12 + v14 + a1) / 100;

	a3 = 6 * (v21 + v1 + v4) + v1Last + v41 + v3;
	if (val2 == 3)
		a3 = (15 * v2 + a3) / 36;
	else if (val2 == 4)
		a3 = (36 * v2 + 6 * (v23) + v22 + a3) / 64;
	else
		a3 = (65 * v2 + 6 * (v23 + v25) + v22 + v24 + a3) / 100;

	a7 = 6 * (v31 + v1 + v4) + v4Last + v11 + v2;
	if (val3 == 3)
		a7 = (15 * v3 + a7) / 36;
	else if (val3 == 4)
		a7 = (36 * v3 + 6 * (v33) + v32 + a7) / 64;
	else
		a7 = (65 * v3 + 6 * (v33 + v35) + v32 + v34 + a7) / 100;

	a9 = 6 * (v41 + v2 + v3) + v2Last + v31 + v1;
	if (val4 == 3)
		a9 = (15 * v4 + a9) / 36;
	else if (val4 == 4)
		a9 = (36 * v4 + 6 * (v43) +  v42 + a9) / 64;
	else
		a9 = (65 * v4 + 6 * (v43 + v45) +  v42 + v44 + a9) / 100;
*/




		

	// until here: this was the level1 subdivision, which calculated a1..a9


	float3 A11 = (v3Last + v11 + v1 + v3) / 4.0f;
	float3 A12 = (v11 + v12 + v13 + v1) / 4.0f;
	float3 A13 = (v13 + v14 + v15 + v1) / 4.0f;
	          
	float3 A31 = (v1Last + v21 + v2 + v1) / 4.0f;
	float3 A32 = (v21 + v22 + v23 + v2) / 4.0f;
	float3 A33 = (v23 + v24 + v25 + v2) / 4.0f;

	float3 A71 = (v4Last + v31 + v3 + v4) / 4.0f;
	float3 A72 = (v31 + v32 + v33 + v3) / 4.0f;
	float3 A73 = (v33 + v34 + v35 + v3) / 4.0f;

	float3 A91 = (v2Last + v41 + v4 + v2) / 4.0f;
	float3 A92 = (v41 + v42 + v43 + v4) / 4.0f;
	float3 A93 = (v43 + v44 + v45 + v4) / 4.0f;

	// *****
	float3 AA11 = (A11 + A12 + v11 + v1) / 4.0f;
	float3 AA12 = (A12 + A13 + v13 + v1) / 4.0f;
	float3 AA1Last;
	if (val1 == 3)
		AA1Last = (A11 + A31 + v11 + v1) / 4.0f;
	else if (val1 == 4)
		AA1Last = (A12 + A31 + v13 + v1) / 4.0f;
	else
		AA1Last = (A13 + A31 + v15 + v1) / 4.0f;
	float3 AA1First;
	if (val1 == 3)
		AA1First = (A11 + A31 + v11 + v1) / 4.0f;
	else
		AA1First = (A11 + A12 + v11 + v1) / 4.0f;

	float3 AA31 = (A31 + A32 + v21 + v2) / 4.0f;
	float3 AA32 = (A32 + A33 + v23 + v2) / 4.0f;
	float3 AA3Last;
	if (val2 == 3)
		AA3Last = (A31 + A91 + v21 + v2) / 4.0f;
	else if (val2 == 4)
		AA3Last = (A32 + A91 + v23 + v2) / 4.0f;
	else
		AA3Last = (A33 + A91 + v25 + v2) / 4.0f;
	float3 AA3First;
	if (val2 == 3)
		AA3First = (A31 + A91 + v21 + v2) / 4.0f;
	else
		AA3First = (A31 + A32 + v21 + v2) / 4.0f;

	float3 AA91 = (A91 + A92 + v41 + v4) / 4.0f;
	float3 AA92 = (A92 + A93 + v43 + v4) / 4.0f;
	float3 AA9Last;
	if (val4 == 3)
		AA9Last = (A91 + A71 + v41 + v4) / 4.0f;
	else if (val4 == 4)
		AA9Last = (A92 + A71 + v43 + v4) / 4.0f;
	else
		AA9Last = (A93 + A71 + v45 + v4) / 4.0f;
	float3 AA9First;
	if (val4 == 3)
		AA9First = (A91 + A71 + v41 + v4) / 4.0f;
	else
		AA9First = (A91 + A92 + v41 + v4) / 4.0f;

	float3 AA71 = (A71 + A72 + v31 + v3) / 4.0f;
	float3 AA72 = (A72 + A73 + v33 + v3) / 4.0f;
	float3 AA7Last;
	if (val3 == 3)
		AA7Last = (A71 + A11 + v31 + v3) / 4.0f;
	else if (val3 == 4)
		AA7Last = (A72 + A11 + v33 + v3) / 4.0f;
	else
		AA7Last = (A73 + A11 + v35 + v3) / 4.0f;
	float3 AA7First;
	if (val3 == 3)
		AA7First = (A71 + A11 + v31 + v3) / 4.0f;
	else
		AA7First = (A71 + A72 + v31 + v3) / 4.0f;


	// calculate positions b1..b25 now 	
/*
	float3 b1 = a1;
	float3 b2 = (a1 + a2) / 2.0f;
	float3 b3 = a2;
	float3 b4 = (a2 + a3) / 2.0f;
	float3 b5 = a3;
	float3 b6 = (a1 + a4) / 2.0f;
	float3 b7 = (a1 + a2 + a4 + a5) / 4.0f;
	float3 b8 = (a2 + a5) / 2.0f;
	float3 b9 = (a2 + a3 + a5 + a6) / 4.0f;
	float3 b10 = (a3 + a6) / 2.0f;
	float3 b11 = a4;
	float3 b12 = (a4 + a5) / 2.0f;
	float3 b13 = a5;
	float3 b14 = (a5 + a6) / 2.0f;
	float3 b15 = a6;
	float3 b16 = (a4 + a7) / 2.0f;
	float3 b17 = (a4 + a5 + a7 + a8) / 4.0f;
	float3 b18 = (a5 + a8) / 2.0f;
	float3 b19 = (a5 + a6 + a8 + a9) / 4.0f;
	float3 b20 = (a6 + a9) / 2.0f;
	float3 b21 = a7;
	float3 b22 = (a7 + a8) / 2.0f;
	float3 b23 = a8;
	float3 b24 = (a8 + a9) / 2.0f;
	float3 b25 = a9;
	*/
	
	
	float3 b1;
	float3 b2;
	float3 b3;
	float3 b4;
	float3 b5;
	float3 b6;
	float3 b7;
	float3 b8;
	float3 b9;
	float3 b10;
	float3 b11;
	float3 b12;
	float3 b13;
	float3 b14;
	float3 b15;
	float3 b16;
	float3 b17;
	float3 b18;
	float3 b19;
	float3 b20;
	float3 b21;
	float3 b22;
	float3 b23;
	float3 b24;
	float3 b25;
	
	//*****************
	b7 = (a1 + a2 + a4 + a5) / 4;
	b9 = (a2 + a3 + a5 + a6) / 4;
	b17 = (a4 + a5 + a7 + a8) / 4;
	b19 = (a5 + a6 + a8 + a9) / 4;
	b8 = (a2 + a5 + b7 + b9) / 4;
	b12 = (a4 + a5 + b7 + b17) / 4;
	b14 = (a5 + a6 + b9 + b19) / 4;
	b18 = (a5 + a8 + b17 + b19) / 4;
	b13 = 0.5f * a5 + (b7 + b8 + b9 + b12 + b14 + b17 + b18 + b19) / 16;

	// *****
	b2 = (a1 + a2 + b7 + (a1 + a2 + A31 + AA1Last) / 4) / 4;
	b4 = (a2 + a3 + b9 + (a2 + a3 + A31 + AA3First) / 4) / 4;
	b3 = (36 * a2 + 6 * (a1 + a3 + a5 + A31) + a4 + a6 + AA1Last + AA3First) / 64;
	if (val1 == 3)
		b1 = (15 * a1 + 6 * (AA1Last + a2 + a4) + A11 + a5 + A31) / 36;
	else if (val1 == 4)
		b1 = (36 * a1 + 6 * (AA11 + AA1Last + a2 + a4) + A11 + A12 + a5 + A31) / 64;
	else		
		b1 = (65 * a1 + 6 * (AA11 + AA12 + AA1Last + a2 + a4) + A11 + A12 + A13 + a5 + A31) / 100;

	b10 = (a3 + a6 + b9 + (a3 + a6 + A91 + AA3Last) / 4) / 4;
	b20 = (a6 + a9 + b19 + (a6 + a9 + A91 + AA9First) / 4) / 4;
	b15 = (36 * a6 + 6 * (a5 + a3 + a9 + A91) + a2 + a8 + AA3Last + AA9First) / 64;
	if (val2 == 3)
		b5 = (15 * a3 + 6 * (AA3Last + a2 + a6) + A31 + a5 + A91) / 36;
	else if (val2 == 4)
		b5 = (36 * a3 + 6 * (AA31 + AA3Last + a2 + a6) + A31 + A32 + a5 + A91) / 64;
	else
		b5 = (65 * a3 + 6 * (AA31 + AA32 + AA3Last + a2 + a6) + A31 + A32 + A33 + a5 + A91) / 100;

	b16 = (a4 + a7 + b17 + (a4 + a7 + A11 + AA7Last) / 4) / 4;
	b6 = (a1 + a4 + b7 + (a1 + a4 + A11 + AA1First) / 4) / 4;
	b11 = (36 * a4 + 6 * (a1 + a5 + a7 + A11) + a2 + a8 + AA7Last + AA1First) / 64;
	if (val3 == 3)
		b21 = (15 * a7 + 6 * (AA7Last + a4 + a8) + A71 + a5 + A11) / 36;
	else if (val3 == 4)
		b21 = (36 * a7 + 6 * (AA71 + AA7Last + a4 + a8) + A71 + A72 + a5 + A11) / 64;
	else
		b21 = (65 * a7 + 6 * (AA71 + AA72 + AA7Last + a4 + a8) + A71 + A72 + A73 + a5 + A11) / 100;
		
	b24 = (a8 + a9 + b19 + (a8 + a9 + A71 + AA9Last) / 4) / 4;
	b22 = (a7 + a8 + b17 + (a7 + a8 + A71 + AA7First) / 4) / 4;
	b23 = (36 * a8 + 6 * (a5 + a7 + a9 + A71) + a4 + a6 + AA9Last + AA7First) / 64;
	if (val4 == 3)
		b25 = (15 * a9 + 6 * (AA9Last + a6 + a8) + A91 + a5 + A71) / 36;
	else if (val4 == 4)
		b25 = (36 * a9 + 6 * (AA91 + AA9Last + a6 + a8) + A91 + A92 + a5 + A71) / 64;
	else
		b25 = (65 * a9 + 6 * (AA91 + AA92 + AA9Last + a6 + a8) + A91 + A92 + A93 + a5 + A71) / 100;
	



	// ********** texture and normal
	float2 t1 = g_texUvBuffer.Load(texInd.x);
	float2 t5 = g_texUvBuffer.Load(texInd.y);
	float2 t21 = g_texUvBuffer.Load(texInd.z);
	float2 t25 = g_texUvBuffer.Load(texInd.w);
	float2 t11 = (t1 + t21) / 2.0f;
	float2 t6 = (t1 + t11) / 2.0f;
	float2 t16 = (t11 + t21) / 2.0f;
	float2 t15 = (t5 + t25) / 2.0f;
	float2 t10 = (t5 + t15) / 2.0f;
	float2 t20 = (t15 + t25) / 2.0f;
	float2 t3 = (t1 + t5) / 2.0f;
	float2 t2 = (t1 + t3) / 2.0f;
	float2 t4 = (t3 + t5) / 2.0f;
	float2 t8 = (t6 + t10) / 2.0f;
	float2 t7 = (t6 + t8) / 2.0f;
	float2 t9 = (t8 + t10) / 2.0f;
	float2 t13 = (t11 + t15) / 2.0f;
	float2 t12 = (t11 + t13) / 2.0f;
	float2 t14 = (t13 + t15) / 2.0f;
	float2 t18 = (t16 + t20) / 2.0f;
	float2 t17 = (t16 + t18) / 2.0f;
	float2 t19 = (t18 + t20) / 2.0f;
	float2 t23 = (t21 + t25) / 2.0f;
	float2 t22 = (t21 + t23) / 2.0f;
	float2 t24 = (t23 + t25) / 2.0f;

	float3 n1 = g_normalBuffer.Load(normalInd.x);
	float3 n5 = g_normalBuffer.Load(normalInd.y);
	float3 n21 = g_normalBuffer.Load(normalInd.z);
	float3 n25 = g_normalBuffer.Load(normalInd.w);
	float3 n11 = (n1 + n21) / 2.0f;
	float3 n6 = (n1 + n11) / 2.0f;
	float3 n16 = (n11 + n21) / 2.0f;
	float3 n15 = (n5 + n25) / 2.0f;
	float3 n10 = (n5 + n15) / 2.0f;
	float3 n20 = (n15 + n25) / 2.0f;
	float3 n3 = (n1 + n5) / 2.0f;
	float3 n2 = (n1 + n3) / 2.0f;
	float3 n4 = (n3 + n5) / 2.0f;
	float3 n8 = (n6 + n10) / 2.0f;
	float3 n7 = (n6 + n8) / 2.0f;
	float3 n9 = (n8 + n10) / 2.0f;
	float3 n13 = (n11 + n15) / 2.0f;
	float3 n12 = (n11 + n13) / 2.0f;
	float3 n14 = (n13 + n15) / 2.0f;
	float3 n18 = (n16 + n20) / 2.0f;
	float3 n17 = (n16 + n18) / 2.0f;
	float3 n19 = (n18 + n20) / 2.0f;
	float3 n23 = (n21 + n25) / 2.0f;
	float3 n22 = (n21 + n23) / 2.0f;
	float3 n24 = (n23 + n25) / 2.0f;
	
	float3 tan1 = g_tangentBuffer.Load(tangentInd.x);
	float3 tan5 = g_tangentBuffer.Load(tangentInd.y);
	float3 tan21 = g_tangentBuffer.Load(tangentInd.z);
	float3 tan25 = g_tangentBuffer.Load(tangentInd.w);
	float3 tan11 = (tan1 + tan21) / 2.0f;
	float3 tan6 = (tan1 + tan11) / 2.0f;
	float3 tan16 = (tan11 + tan21) / 2.0f;
	float3 tan15 = (tan5 + tan25) / 2.0f;
	float3 tan10 = (tan5 + tan15) / 2.0f;
	float3 tan20 = (tan15 + tan25) / 2.0f;
	float3 tan3 = (tan1 + tan5) / 2.0f;
	float3 tan2 = (tan1 + tan3) / 2.0f;
	float3 tan4 = (tan3 + tan5) / 2.0f;
	float3 tan8 = (tan6 + tan10) / 2.0f;
	float3 tan7 = (tan6 + tan8) / 2.0f;
	float3 tan9 = (tan8 + tan10) / 2.0f;
	float3 tan13 = (tan11 + tan15) / 2.0f;
	float3 tan12 = (tan11 + tan13) / 2.0f;
	float3 tan14 = (tan13 + tan15) / 2.0f;
	float3 tan18 = (tan16 + tan20) / 2.0f;
	float3 tan17 = (tan16 + tan18) / 2.0f;
	float3 tan19 = (tan18 + tan20) / 2.0f;
	float3 tan23 = (tan21 + tan25) / 2.0f;
	float3 tan22 = (tan21 + tan23) / 2.0f;
	float3 tan24 = (tan23 + tan25) / 2.0f;



	// first row
	output.PosInWorld = b1;
	output.Pos = mul(float4(b1.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t1;
	output.NormalInWorld = n1;
	output.TangentInWorld = tan1;
	p_stream.Append(output);

	output.PosInWorld = b6;
	output.Pos = mul(float4(b6.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t6;
	output.NormalInWorld = n6;
	output.TangentInWorld = tan6;
	p_stream.Append(output);
	
	output.PosInWorld = b2;
	output.Pos = mul(float4(b2.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t2;
	output.NormalInWorld = n2;
	output.TangentInWorld = tan2;
	p_stream.Append(output);

	output.PosInWorld = b7;
	output.Pos = mul(float4(b7.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t7;
	output.NormalInWorld = n7;
	output.TangentInWorld = tan7;
	p_stream.Append(output);
	
	output.PosInWorld = b3;
	output.Pos = mul(float4(b3.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t3;
	output.NormalInWorld = n3;
	output.TangentInWorld = tan3;
	p_stream.Append(output);

	output.PosInWorld = b8;
	output.Pos = mul(float4(b8.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t8;
	output.NormalInWorld = n8;
	output.TangentInWorld = tan8;
	p_stream.Append(output);
	
	output.PosInWorld = b4;
	output.Pos = mul(float4(b4.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t4;
	output.NormalInWorld = n4;
	output.TangentInWorld = tan4;
	p_stream.Append(output);

	output.PosInWorld = b9;
	output.Pos = mul(float4(b9.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t9;
	output.NormalInWorld = n9;
	output.TangentInWorld = tan9;
	p_stream.Append(output);
	
	output.PosInWorld = b5;
	output.Pos = mul(float4(b5.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t5;
	output.NormalInWorld = n5;
	output.TangentInWorld = tan5;
	p_stream.Append(output);

	output.PosInWorld = b10;
	output.Pos = mul(float4(b10.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t10;
	output.NormalInWorld = n10;
	output.TangentInWorld = tan10;
	p_stream.Append(output);

	p_stream.RestartStrip(); 

	// second row
	output.PosInWorld = b6;
	output.Pos = mul(float4(b6.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t6;
	output.NormalInWorld = n6;
	output.TangentInWorld = tan6;
	p_stream.Append(output);

	output.PosInWorld = b11;
	output.Pos = mul(float4(b11.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t11;
	output.NormalInWorld = n11;
	output.TangentInWorld = tan11;
	p_stream.Append(output);
	
	output.PosInWorld = b7;
	output.Pos = mul(float4(b7.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t7;
	output.NormalInWorld = n7;
	output.TangentInWorld = tan7;
	p_stream.Append(output);

	output.PosInWorld = b12;
	output.Pos = mul(float4(b12.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t12;
	output.NormalInWorld = n12;
	output.TangentInWorld = tan12;
	p_stream.Append(output);
	
	output.PosInWorld = b8;
	output.Pos = mul(float4(b8.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t8;
	output.NormalInWorld = n8;
	output.TangentInWorld = tan8;
	p_stream.Append(output);

	output.PosInWorld = b13;
	output.Pos = mul(float4(b13.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t13;
	output.NormalInWorld = n13;
	output.TangentInWorld = tan13;
	p_stream.Append(output);
	
	output.PosInWorld = b9;
	output.Pos = mul(float4(b9.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t9;
	output.NormalInWorld = n9;
	output.TangentInWorld = tan9;
	p_stream.Append(output);

	output.PosInWorld = b14;
	output.Pos = mul(float4(b14.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t14;
	output.NormalInWorld = n14;
	output.TangentInWorld = tan14;
	p_stream.Append(output);
	
	output.PosInWorld = b10;
	output.Pos = mul(float4(b10.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t10;
	output.NormalInWorld = n10;
	output.TangentInWorld = tan10;
	p_stream.Append(output);

	output.PosInWorld = b15;
	output.Pos = mul(float4(b15.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t15;
	output.NormalInWorld = n15;
	output.TangentInWorld = tan15;
	p_stream.Append(output);

	p_stream.RestartStrip(); 

	// third row
	output.PosInWorld = b11;
	output.Pos = mul(float4(b11.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t11;
	output.NormalInWorld = n11;
	output.TangentInWorld = tan11;
	p_stream.Append(output);

	output.PosInWorld = b16;
	output.Pos = mul(float4(b16.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t16;
	output.NormalInWorld = n16;
	output.TangentInWorld = tan16;
	p_stream.Append(output);
	
	output.PosInWorld = b12;
	output.Pos = mul(float4(b12.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t12;
	output.NormalInWorld = n12;
	output.TangentInWorld = tan12;
	p_stream.Append(output);

	output.PosInWorld = b17;
	output.Pos = mul(float4(b17.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t17;
	output.NormalInWorld = n17;
	output.TangentInWorld = tan17;
	p_stream.Append(output);
	
	output.PosInWorld = b13;
	output.Pos = mul(float4(b13.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t13;
	output.NormalInWorld = n13;
	output.TangentInWorld = tan13;
	p_stream.Append(output);

	output.PosInWorld = b18;
	output.Pos = mul(float4(b18.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t18;
	output.NormalInWorld = n18;
	output.TangentInWorld = tan18;
	p_stream.Append(output);
	
	output.PosInWorld = b14;
	output.Pos = mul(float4(b14.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t14;
	output.NormalInWorld = n14;
	output.TangentInWorld = tan14;
	p_stream.Append(output);

	output.PosInWorld = b19;
	output.Pos = mul(float4(b19.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t19;
	output.NormalInWorld = n19;
	output.TangentInWorld = tan19;
	p_stream.Append(output);
	
	output.PosInWorld = b15;
	output.Pos = mul(float4(b15.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t15;
	output.NormalInWorld = n15;
	output.TangentInWorld = tan15;
	p_stream.Append(output);

	output.PosInWorld = b20;
	output.Pos = mul(float4(b20.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t20;
	output.NormalInWorld = n20;
	output.TangentInWorld = tan20;
	p_stream.Append(output);

	p_stream.RestartStrip(); 

	// fourth row
	output.PosInWorld = b16;
	output.Pos = mul(float4(b16.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t16;
	output.NormalInWorld = n16;
	output.TangentInWorld = tan16;
	p_stream.Append(output);

	output.PosInWorld = b21;
	output.Pos = mul(float4(b21.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t21;
	output.NormalInWorld = n21;
	output.TangentInWorld = tan21;
	p_stream.Append(output);
	
	output.PosInWorld = b17;
	output.Pos = mul(float4(b17.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t17;
	output.NormalInWorld = n17;
	output.TangentInWorld = tan17;
	p_stream.Append(output);

	output.PosInWorld = b22;
	output.Pos = mul(float4(b22.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t22;
	output.NormalInWorld = n22;
	output.TangentInWorld = tan22;
	p_stream.Append(output);
		
	output.PosInWorld = b18;
	output.Pos = mul(float4(b18.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t18;
	output.NormalInWorld = n18;
	output.TangentInWorld = tan18;
	p_stream.Append(output);

	output.PosInWorld = b23;
	output.Pos = mul(float4(b23.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t23;
	output.NormalInWorld = n23;
	output.TangentInWorld = tan23;
	p_stream.Append(output);

	output.PosInWorld = b19;
	output.Pos = mul(float4(b19.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t19;
	output.NormalInWorld = n19;
	output.TangentInWorld = tan19;
	p_stream.Append(output);

	output.PosInWorld = b24;
	output.Pos = mul(float4(b24.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t24;
	output.NormalInWorld = n24;
	output.TangentInWorld = tan24;
	p_stream.Append(output);
	
	output.PosInWorld = b20;
	output.Pos = mul(float4(b20.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t20;
	output.NormalInWorld = n20;
	output.TangentInWorld = tan20;
	p_stream.Append(output);

	output.PosInWorld = b25;
	output.Pos = mul(float4(b25.xyz, 1.0), g_mWorldViewProj);
	output.TexUv = t25;
	output.NormalInWorld = n25;
	output.TangentInWorld = tan25;
	p_stream.Append(output);

	p_stream.RestartStrip(); 
}


//
// Geometry shader
//
// input notation:
//  1 ----  2
//  |    /  |
//  |  /    |
//  3 ----  4
// output notation to pixel shader:
//  0 ----  1
//  |    /  |
//  |  /    |
//  3 ----  2
// triangle strip must begin with the clockwise order (0, 1, 3 is clockWise)
// since DirectX is deafault: Left handed, frontFace = ClockWise

[maxvertexcount(4)]
void GSMainLevel0(point GS_INPUT input[1], inout TriangleStream<PS_INPUT> p_stream)
{
	Subdiv0Function(input[0].QuadIndex, p_stream);
}

[maxvertexcount(12)]
void GSMainLevel1(point GS_INPUT input[1], inout TriangleStream<PS_INPUT> p_stream)
{
	Subdiv1Function(input[0].QuadIndex, p_stream);
}

[maxvertexcount(40)]
void GSMainLevel2(point GS_INPUT input[1], inout TriangleStream<PS_INPUT> p_stream)
{
   Subdiv2Function(input[0].QuadIndex, p_stream);
}



// for the cube: bumpness = 8.0, specular shininess = 6.0
// for the lizard: bumpness = 1.0, specular shininess = 16.0
float4 PSMain(PS_INPUT input) : SV_Target
{
	float4 diffuseTexture = g_texDiffuse.Sample(g_diffuseSampler, float2(input.TexUv.xy));
	//diffuseTexture = float4(0.5, 0.5, 0.5, 1);
	float3 normalMap = g_texNormalMap.Sample(g_normalMapSampler, float2(input.TexUv.xy));
	
	// for monsterfrog-n.bmp, we need to transfer the green component, it in in OpenGL texture coordinate system
	// for FieldstoneBumpDOT3.jpg, the green component is ok
	//normalMap.y *= -1; // stupid, for the lizard normalMap only
	
	// the general pixels of the NormalMap is RGB = (128, 128, 255), which should be transformed to (0, 0, 1)
	float3 normalInTangent = 2 * normalMap - 1;
	normalInTangent.y *= -1; // stupid, for the lizard normalMap only
		
	float bumpness = 1.0;		// do not put the bumpiness higher than 1 for the lizard bumpmap, it couse to much disturbation
	
	float3 normal = normalize(input.NormalInWorld);
	float3 tangent = normalize(input.TangentInWorld);
	float3 bitangent = normalize(cross(normal, tangent));
	 ///float3 perturbedNormalInWorld = normalize(normalInTangent.x * tangent + normalInTangent.y * bitangent + normalInTangent.z * normal);
    float3 perturbedNormalInWorld = normalize(bumpness * normalInTangent.x * tangent + bumpness * normalInTangent.y * bitangent + normalInTangent.z * normal);
    
    //perturbedNormalInWorld = normal;
	
	//diffuse lighting	
	float3 lightDirNormalized = normalize(g_lightInvDirNormalized);
    float cosAlfa = saturate(dot(lightDirNormalized, perturbedNormalInWorld));
    float4 diffusePart = 1 * cosAlfa * g_lightDiffuseColor * g_kDiffuse;
       	
	// Calculate specular power
	float3 viewDir = normalize(g_vEyePt - input.PosInWorld);
	float3 halfAngle = normalize(viewDir + lightDirNormalized);
	//float4 specularPart = 1.5 * saturate(pow(dot(halfAngle, normal), 64));
	//float4 specularPart = saturate(pow(dot(halfAngle, normal), 2));
	//float dotValue = saturate(dot(halfAngle, normal));
	float dotValue = saturate(dot(halfAngle, perturbedNormalInWorld));
	//float4 specularPart = 1.5 * saturate(pow(dotValue, 64));
	float4 specularPart = 1.5 * g_kSpecular * saturate(pow(dotValue, 16));
	
	float4 result = diffuseTexture * (0.5 * g_ambient  + 2 * diffusePart) + specularPart;
	return float4(result.xyz, 1);
}


//--------------------------------------------------------------------------------------
technique10 RenderLevel0
{
    pass P0
    {
        SetVertexShader(CompileShader(vs_4_0, VSMain()));
        SetGeometryShader(CompileShader(gs_4_0, GSMainLevel0()));
        SetPixelShader(CompileShader(ps_4_0, PSMain()));
    }
}

//--------------------------------------------------------------------------------------
technique10 RenderLevel1
{
    pass P0
    {
        SetVertexShader(CompileShader(vs_4_0, VSMain()));
        SetGeometryShader(CompileShader(gs_4_0, GSMainLevel1()));
        SetPixelShader(CompileShader(ps_4_0, PSMain()));
    }
}


//--------------------------------------------------------------------------------------
technique10 RenderLevel2
{
    pass P0
    {
        SetVertexShader(CompileShader(vs_4_0, VSMain()));
        SetGeometryShader(CompileShader(gs_4_0, GSMainLevel2()));
        SetPixelShader(CompileShader(ps_4_0, PSMain()));
    }
}




